package com.billard.config;

import com.billard.properties.JwtProperties;
import com.billard.mapper.UserMapper;
import com.billard.entity.User;
import com.billard.result.Result;
import com.billard.utils.JwtUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
//2 过滤器
    private final JwtProperties jwtProperties;
    private final UserMapper userMapper;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public JwtAuthenticationFilter(JwtProperties jwtProperties, UserMapper userMapper) {
        this.jwtProperties = jwtProperties;
        this.userMapper = userMapper;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        // 白名单：不需要 JWT 认证的路径
        String requestURI = request.getRequestURI();
        if (isPublicUri(requestURI)) {
            filterChain.doFilter(request, response); // 直接放行
            return;
        }

        String token = request.getHeader(jwtProperties.getTokenName());
        if ((token == null || token.isEmpty())) {
            // 兼容 WebSocket 等通过查询参数传递 token 的场景
            String qpToken = request.getParameter(jwtProperties.getTokenName());
            if (qpToken == null || qpToken.isEmpty()) {
                qpToken = request.getParameter("token");
            }
            token = qpToken;
        }

        // 去除 Bearer 前缀
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }

        log.info("JWT过滤器请求路径: {}, JWT: {}", requestURI, token);

        if (token != null && !token.isEmpty()) {
            try {
                Map<String, Object> claims = JwtUtil.parseJWT(jwtProperties.getSecretKey(), token);
                String username = claims.get("username").toString();
                log.info("JWT 解析成功, 用户名: {}", username);
                User user = userMapper.selectByUsername(username);
                if (user != null) {
                    List<String> permissions = userMapper.selectPermissionsByUserId(user.getId());
                    log.info("用户 {} 权限: {}", username, permissions);

                    // 如果是 admin，自动放行所有权限

                    UsernamePasswordAuthenticationToken auth =
                            new UsernamePasswordAuthenticationToken(
                                    username,
                                    null,
                                    permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())
                            );
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }

            } catch (Exception e) {
                log.warn("JWT 验证失败: {}", e.getMessage());
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType("application/json;charset=UTF-8");
                Result<Void> result = Result.error(401, "JWT无效或已过期");
                response.getWriter().write(objectMapper.writeValueAsString(result));
                return;
            }
        }

        filterChain.doFilter(request, response);
    }

    // 判断是否为公开路径
    private boolean isPublicUri(String uri) {
        return uri.startsWith("/user/login") ||
                uri.startsWith("/user/create") ||
                uri.startsWith("/health") ||
                uri.startsWith("/v3/api-docs") ||
                uri.startsWith("/swagger-ui") ||
                uri.startsWith("/doc.html");
    }
}
